package idc

import (
	"errors"
	"fmt"
	"sync"
	"time"
)

/*
组成：0(1 bit) | timestamp in milli second (41 bit) | machine id (10 bit) | index (12 bit)
每毫秒最多生成4096个id，集群机器最多1024台
*/

const (
	Epoch           int64 = 1628145004226 // 2021/08/05 下午
	NodeAndStepBits uint8 = 22

	NodeBits uint8 = 10 // 2^10 = 1024 个节点，每个节点每毫秒可以产生 2^(22-10) = 4096 个 ID
)

type Node struct {
	mu sync.Mutex
	// lastTimestamp int64
	epoch     time.Time
	time      int64
	nodeIndex int64
	// nodeMax       int64
	step int64

	stepMask  int64
	timeShift uint8
	nodeShift uint8
}

func NewNode(nodeIndex int64, nodeBits uint8) (*Node, error) {
	if nodeBits <= 0 || nodeBits >= NodeAndStepBits {
		return nil, errors.New("node bits must between 1 and 21")
	}
	var nodeMax int64 = -1 ^ (-1 << nodeBits)
	if nodeIndex < 0 || nodeIndex > nodeMax {
		return nil, fmt.Errorf("node index must be between 0 and %d", nodeMax)
	}

	var stepBits uint8 = NodeAndStepBits - nodeBits

	var cur = time.Now()
	// add time.Duration to curTime to make sure we use the monotonic clock if available
	epoch := cur.Add(time.Unix(Epoch/1000, (Epoch%1000)*1000000).Sub(cur))
	return &Node{
		epoch:     epoch,
		nodeIndex: nodeIndex,
		stepMask:  -1 ^ (-1 << stepBits),

		timeShift: nodeBits + stepBits,
		nodeShift: nodeBits,
	}, nil
}

func (n *Node) Generate() int64 {
	n.mu.Lock()

	now := time.Since(n.epoch).Nanoseconds() / 1000000
	if now == n.time {
		n.step = (n.step + 1) & n.stepMask
		if n.step == 0 {
			for now <= n.time {
				now = time.Since(n.epoch).Nanoseconds() / 1000000
			}
		}
	} else {
		n.step = 0
	}

	n.time = now

	r := int64((now)<<n.timeShift |
		(n.nodeIndex << n.nodeShift) |
		(n.step),
	)

	n.mu.Unlock()
	return r
}

func (n *Node) ParseTime(id int64) int64 {
	return (id >> n.timeShift) + Epoch
}
